var l = console.log;
var { curry } = require("lodash");
// var compose = (f, g) => (x) => f(g(x));
var compose = (...args) => (...arguments) =>
  args.reduceRight((memo, cur) =>
    cur(typeof memo === "function" ? memo.apply(memo, arguments) : memo)
  );

var toLowerCase = (x) => x.toLowerCase();
var toUpperCase = (x) => x.toUpperCase();
var head = (arr) => arr[0];
var replace = curry((pattern, replacement, str) =>
  str.replace(pattern, replacement)
);

//这里所做的事情就是通过管道把数据在接受单个参数的函数间传递。利用 curry，我们能够做到让每个函数都先接收数据，然后操作数据，最后再把数据传递到下一个函数那里去。另外注意在 pointfree 版本中，不需要 word 参数就能构造函数；而在非 pointfree 的版本中，必须要有 word 才能进行一切操作。

// 非 pointfree，因为提到了数据：word
var snakeCase = function (word) {
  return word.toLowerCase().replace(/\s+/gi, "_");
};

// pointfree 把 空格 替换成 _
var snakeCase = compose(replace(/\s+/gi, "_"), toLowerCase);

l(snakeCase("snake snape"));

var split = curry((x, str) => str.split(x));
var map = curry((f, arr) => arr.map(f));
var join = curry((joiner, arr) => arr.join(joiner));

// 非 pointfree，因为提到了数据：name
var initials = function (name) {
  return name.split(" ").map(compose(toUpperCase, head)).join(". ");
};

// pointfree
var initials = compose(join(". "), map(compose(toUpperCase, head)), split(" "));

l(initials("hunter stockton thompson"));
// 'H. S. T'
var exclaim = (x) => x + "!";
var reduce = curry((f, init, arr) => arr.reduce(f, init));
var reverse = reduce((memo, cur) => [cur].concat(memo), []);
// l(reduce)
var angry = compose(toUpperCase, exclaim);
// 错误做法：我们传给了 `angry` 一个数组，根本不知道最后传给 `map` 的是什么东西。

var latin = compose(map, trace("after angry:"), angry, reverse);
//["frog", "eyes"]+"!"
// "frog,eyes!"

latin(["frog", "eyes"]);
// l(latin(["frog", "eyes"]))
// error

// 正确做法：每个函数都接受一个实际参数。
var latin = compose(map(angry), reverse);

l(latin(["frog", "eyes"]));
// ["EYES!", "FROG!"])

//如果在 debug 组合的时候遇到了困难，那么可以使用下面这个实用的，但是不纯的 trace 函数来追踪代码的执行情况。
var trace = curry(function (tag, x) {
  console.log(tag, x);
  return x;
});
